package cn.jdemo.juc.condition;

/**
 * 使用object的方法
 * wait() 和notify() 或者 notifyAll() 进行搭配的时候必须在synchronized（obj）模块里  (注：这里的obj为任意一对象)，
 *
 * 切调用wait() notify()，notifyAll()的对象要同一（注：为相同的对象。）
 *
 * wait() notify()，notifyAll()这三个方法的作用范围：必须在同一个main方法里，否者无效。（请看demoZH01，demoZH02，demoZH02）.
 *
 * 调用notify()时：恢复第一个调用wait（）方法的线程，其他的线程不恢复。（注：每个调用wait()方法的对象要同一，即都是相同的一个对象。调用notify()方法的对象  和  调用wait()方法的对象    要一样）
 *
 * 调用notifyAll()时：恢复所有调用wait()方法的线程。（注：每个调用wait()方法的对象要同一，即都是相同的一个对象。调用notifyAll()方法的对象  和  调用wait()方法的对象    要一样）
 *
 * 调用wait方法时：会释放当前的锁对象并加入该对象的等待池中。只有针对此对象调用notify()或者notifyAll()方法后本线程才进入对象锁池准备竞争对象锁 当锁池中的线程获得锁后，才开始准备恢复执行操作（这也是必须在synchronized（obj）模块里的原因，当线程唤醒后已经获得了对象锁，并且此时的线程处于synchronized（obj）模块里，假如线程没有在synchronized（obj）模块里，那锁对象所对应的线程进入到锁池中并获得锁 就没有意义了。同时java语言规定 wait() notify()，notifyAll()要在 在synchronized（obj）模块里使用，否者会报错的）。在java中，每个对象都有两个池，锁(monitor)池和等待池。
 *
 * 3：注意： 线程的等待与唤醒都与所关联的对象有关， 因为他们依赖 关联对象的两个池，锁(monitor)池和等待池。
 *
 * @description
 * @date 2020/12/4
 */
public class DemoObject01 {

    private static volatile int num = 0;

    public static void main(String[] args) {
        test0();
    }

    public static  void test0(){
        DemoObject01 object01 = new DemoObject01();

        for (int i=0;i<5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000L);
                        object01.get();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            },"threadName_"+i).start();
        }

        for (int j=0;j<2;j++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000L);
                        object01.set();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            },"threadName_"+j).start();
        }
    }

    public synchronized void get() throws InterruptedException {
        if (num <= 0){
            this.wait();
        }
        --num;
        System.out.println("当前消费_"+Thread.currentThread().getName()+":"+num);
    }

    public synchronized void set(){
        ++num;
        System.out.println("当前生产_"+Thread.currentThread().getName()+":"+num);
        this.notify();
    }

}
